package org.springframework.core.type.classwriting;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.springframework.asm.ClassWriter;
import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.asm.Type;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.ParameterMetadata;
import org.springframework.core.type.ServiceMethodMetadata;
import org.springframework.core.type.classreading.ServiceClassMetadataReadingVisitor;
import org.springframework.util.ClassUtils;

import cn.bonoon.kernel.IdGenerator;
import cn.bonoon.kernel.annotations.services.AutoTransform;
import cn.bonoon.kernel.annotations.services.From;
import cn.bonoon.kernel.annotations.services.Select;
import cn.bonoon.kernel.annotations.services.Where;
import cn.bonoon.kernel.bytecode.EntityReader;
import cn.bonoon.kernel.bytecode.asm.AbstractClassWriter;
import cn.bonoon.kernel.events.BaseEvent;
import cn.bonoon.kernel.events.ReadEvent;
import cn.bonoon.kernel.filters.VisibleScopeFilter;
import cn.bonoon.kernel.support.entities.Persistable;
import cn.bonoon.kernel.support.models.Page;
import cn.bonoon.kernel.support.searcher.StandardSearcher;
import cn.bonoon.kernel.util.StringHelper;

/**
 * <font color='red'>请不要格式化代码，谢谢~</font>
 * 
 * @author ocean~
 */
public abstract class AbstractMetadataWriter extends AbstractClassWriter implements AnnotationMetadata {
	
	protected final ServiceClassMetadataReadingVisitor sVisitor;
	protected final ClassLoader classLoader;
	/**
	 * <pre>
	 * 该子类所需要继承的上级父类，如果只定义了标准的接口，则只需要继承框架里相应的父类即可
	 * 如果接口有些方法需要实现的，则需要自己生成父类；最终的子类也需要实现用户实现的部分方法的父类
	 * </pre>
	 */
	protected String parentName;
	protected Class<?> entityClass;
	protected Class<?> parentClass;
	
	/**
	 * 需要被自动实现的接口的方法
	 */
	protected final List<ServiceMethodMetadata> methods;
	protected final Class<?> siClass;
	
	protected final ServiceMethodParser[] parsers = { 
			new EntityResultType(), 
			new PageResultType(),
			new CollectionResultType(),
			new ArrayResultType(),
			new ObjectResultType() 
	};

	public AbstractMetadataWriter(ServiceClassMetadataReadingVisitor sVisitor, Class<?> siClass) {
		super(ClassUtils.convertClassNameToResourcePath(sVisitor.getClassName()));
		this.siClass = siClass;
		this.sVisitor = sVisitor;
		this.classLoader = sVisitor.getClassLoader();
		this.methods = new ArrayList<ServiceMethodMetadata>();
		this.sVisitor.fillMethods(this.methods);
	}

	protected String parseClassName() {
		return sVisitor.getClassName();
	}

	protected abstract String parseParentName();
	protected abstract Class<? extends Persistable> parseEntityClass()throws Exception;
	protected abstract Class<?> parseParentClass()throws Exception;
	
	protected void initBuilder() throws Exception {
		this.className = parseClassName() + "Impl" + IdGenerator.build();
		this.classPath = ClassUtils.convertClassNameToResourcePath(this.className);
		this.parentName = parseParentName();
		this.parentPath = ClassUtils.convertClassNameToResourcePath(parentName);
		this.entityClass = parseEntityClass();
		this.parentClass = parseParentClass(); 
	}

	@Override
	public Class<?> buildClass() throws Exception {
		initBuilder();
		return super.buildClass();
	}

	/**
	 * <pre>
	 * 1.参数用来生成查询条件:
	 *   1.1 查询一个字段
	 *   1.2 使用查询对象
	 * 2.返回结果：
	 *   2.1 单个结果，查询条件后只取第一个结果
	 *   2.2 列表集合结果返回
	 *   2.3 返回结果是一个字段、多个字段(即对象数组)、一个实体或一个普通的对象(通过构造函数进行赋值)
	 *   2.4 可以返回一个finder
	 * </pre>
	 */
	// 未解决：1.类型转换； 2.List<T>中T的类型转换
	@Override
	protected void internalBuild() throws Exception {
		Method[] jmethods = siClass.getDeclaredMethods(); // reflect
//		if (null != jmethods) // ---------------- 用于调试
//			return;
		
		for (ServiceMethodMetadata smm : methods) {
			if (exclude(smm))
				continue;
			
			Object extension = null;
			
			// 1.获取函数的返回类型
			String returnType_name = smm.getReturnType().getClassName();
			
			Class<?> resultType = null;
			java.lang.reflect.Type returnType_reflect = null;
			try {
				resultType = Class.forName(returnType_name);
			} catch (ClassNotFoundException e) {
				returnType_reflect = _getMethodReturnType(smm, jmethods);
				String str_returnType = returnType_reflect.toString();
				try {
					// 数组
					String array_typeDesc = str_returnType.substring(6, str_returnType.length());
					resultType = Class.forName(array_typeDesc);
				} catch (Exception e2) {
					// 基本类型
//					e.printStackTrace();
				}
			} catch (Exception e) {
//				e.printStackTrace();
			}
			
			// 2.如果返回基本类型，传递该类型名称
			if (null == resultType) {
				String[] basic_type_name = { byte.class.getName(), short.class.getName(), int.class.getName(),
						long.class.getName(), float.class.getName(), double.class.getName(), char.class.getName(),
						boolean.class.getName() };
				List<String> basic_type = Arrays.asList(basic_type_name);
				if (basic_type.contains(returnType_name)) {
					extension = returnType_name;
				}
			}

			// 3.如果返回List<T>, 获取 List<T> 的泛型类 T
			if (null != resultType && Collection.class.isAssignableFrom(resultType)) {
				returnType_reflect = _getMethodReturnType(smm, jmethods);
				Class<?> genericType = _getGenericType(returnType_reflect);
				extension = genericType;
			}
			
			// 4.职责链模式循环处理
			for (ServiceMethodParser parser : parsers) {
				if (parser.parser(smm, parentClass, this.entityClass, resultType, this, this.classPath, extension)) {
					break;
				}
			}
		}
	}
	
	// 通过反射获取函数的返回类型
	private java.lang.reflect.Type _getMethodReturnType(ServiceMethodMetadata smm, Method[] jmethods) {
		ParameterMetadata[] parameters = smm.getParameters();
		Method method = null;
		for (Method jm : jmethods) {
			if (smm.getMethodName().equals(jm.getName())) {
				Class<?>[] pts = jm.getParameterTypes();
				int len = parameters.length;
				if (len == pts.length) {
					int i;
					for (i = 0; i < len; i++) {
						if (!pts[i].getName().equals(parameters[i].getType().getClassName())) {
							break;
						}
					}
					if (i == len) {
						method = jm;
						break;
					}
				}
			}
		}
		return null != method ? method.getGenericReturnType() : null;
	}
	
	// 获取 List<T> 的泛型类 T
	private Class<?> _getGenericType(java.lang.reflect.Type returnType) throws Exception {
		Class<?> genericType = null;
		if (null != returnType && returnType instanceof ParameterizedType) {
			ParameterizedType pt = (ParameterizedType) returnType;
			java.lang.reflect.Type[] typeArguments = pt.getActualTypeArguments();
			for (java.lang.reflect.Type typeArgument : typeArguments) {
				Class<?> typeArgClass = (Class<?>) typeArgument;
				genericType = Class.forName(typeArgClass.getName());
				break;
			}
		}
		return genericType;
	}
	
	// 是否是排除掉的方法
	protected boolean exclude(ServiceMethodMetadata smm) {
		return false;
	}

	@Override
	public String getClassName() {
		return className;
	}

	@Override
	public boolean isInterface() {
		return false;
	}

	@Override
	public boolean isAbstract() {
		return false;
	}

	@Override
	public boolean isConcrete() {
		return true;
	}

	@Override
	public boolean isFinal() {
		return false;
	}

	@Override
	public boolean isIndependent() {
		return true;
	}

	@Override
	public boolean hasEnclosingClass() {
		return false;
	}

	@Override
	public String getEnclosingClassName() {
		return null;
	}

	@Override
	public boolean hasSuperClass() {
		return true;
	}

	@Override
	public String getSuperClassName() {
		return parentName;
	}

	@Override
	public String[] getInterfaceNames() {
		return interfaces;
	}

	@Override
	public String[] getMemberClassNames() {
		return null;
	}

	@Override
	public Set<String> getAnnotationTypes() {
		return sVisitor.getAnnotationTypes();
	}

	@Override
	public Set<String> getMetaAnnotationTypes(String annotationType) {
		return sVisitor.getMetaAnnotationTypes(annotationType);
	}

	@Override
	public boolean hasAnnotation(String annotationType) {
		return sVisitor.hasAnnotation(annotationType);
	}

	@Override
	public boolean hasMetaAnnotation(String metaAnnotationType) {
		return sVisitor.hasMetaAnnotation(metaAnnotationType);
	}

	@Override
	public boolean isAnnotated(String annotationType) {
		return sVisitor.isAnnotated(annotationType);
	}

	@Override
	public Map<String, Object> getAnnotationAttributes(String annotationType) {
		return sVisitor.getAnnotationAttributes(annotationType);
	}

	@Override
	public Map<String, Object> getAnnotationAttributes(String annotationType, boolean classValuesAsString) {
		return sVisitor.getAnnotationAttributes(annotationType, classValuesAsString);
	}

	@Override
	public boolean hasAnnotatedMethods(String annotationType) {
		return sVisitor.hasAnnotatedMethods(annotationType);
	}

	@Override
	public Set<MethodMetadata> getAnnotatedMethods(String annotationType) {
		return sVisitor.getAnnotatedMethods(annotationType);
	}
}

// 职责链模式(Chain of Responsibility)
interface ServiceMethodParser {
	boolean parser(ServiceMethodMetadata smm, Class<?> parentClass, Class<?> entityClass, Class<?> resultType, ClassWriter cw, String classPath, Object extension) throws Exception;
}

abstract class ResultType implements ServiceMethodParser, Opcodes {
	String ql = "";
	String returnType;
	String annotation_select = Select.class.getName();
	String annotation_from = From.class.getName();
	String annotation_where = Where.class.getName();
	boolean isHasAutoTransform = false; // 是否有 AutoTransform 注解
	Class<?> clazz_transform;  // 对象转换类
	Class<?> parentClass;
	String classPath;
	
	ParameterMetadata[] parameters;
	int parameter_len; // 参数数量
	int var_index; // 方法内的变量，参数数量 + J、D类型的参数数量 + i。使用方法：var_index + i 是第i个变量(e.g. var_index + 1 为第一个变量)
	MethodVisitor mWriter;
	
	@Override
	public boolean parser(ServiceMethodMetadata smm, Class<?> parentClass, Class<?> entityClass, Class<?> resultType, ClassWriter cw, String classPath, Object extension) throws Exception {
		this.isHasAutoTransform = smm.isAnnotated(AutoTransform.class.getName());
		if (this.isHasAutoTransform) {
			Map<String, Object> map = smm.getAnnotationAttributes(AutoTransform.class.getName());
			String autoTransform_val = map.get("value").toString();
			if (!autoTransform_val.equals("class java.lang.Object")) {
				autoTransform_val = autoTransform_val.substring(1, autoTransform_val.length() - 1);
				autoTransform_val = ClassUtils.convertResourcePathToClassName(autoTransform_val); // cn.bonoon.controllers.place.PlaceDetail
				this.clazz_transform = Class.forName(autoTransform_val);
			}
		}
		this.parentClass = parentClass;
		this.classPath = classPath;
		this.returnType = smm.getReturnType().getClassName();
		this.parameters = smm.getParameters();
		this.parameter_len = this.parameters.length;
		this.var_index = this.parameter_len + _parameterJDCount();
		this.mWriter = smm.buildMethod(cw);
		this.mWriter.visitCode();
		return true;
	}
	
	/** 
     * 循环向上转型, 获取对象的 DeclaredMethod 
     * @param methodName : 父类中的方法名 
     * @param parameterTypes : 父类中的方法参数类型 
     * @return 父类中的方法对象 
     */
	protected Method _getDeclaredMethod(String methodName, Class<?>... parameterTypes) {//Class<?> cls, 
		Method method = null;
		for (Class<?> clazz = parentClass; clazz != Object.class; clazz = clazz.getSuperclass()) {
			try {
				method = clazz.getDeclaredMethod(methodName, parameterTypes);
				return method;
			} catch (Exception e) {
				// 这里甚么都不要做！并且这里的异常必须这样写，不能抛出去。
				// 如果这里的异常打印或者往外抛，则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
			}
		}
		return null;
	}
	
	 /** 
     * 循环向上转型, 获取对象的 DeclaredField 
     * @param fieldName : 父类中的属性名 
     * @return 父类中的属性对象 
     */  
	public Field _getDeclaredField(String fieldName) {
		Field field = null;
		for (Class<?> clazz = parentClass; clazz != Object.class; clazz = clazz.getSuperclass()) {
			try {
				field = clazz.getDeclaredField(fieldName);
				return field;
			} catch (Exception e) {
				// 这里甚么都不要做！并且这里的异常必须这样写，不能抛出去。
				// 如果这里的异常打印或者往外抛，则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
			}
		}
		return null;
	}
	
	// 调用 __first() 函数
	protected void _visitMethodInsn__first() throws SecurityException, NoSuchMethodException {
		Method m__first = null;
		if (parameter_len == 0) {m__first = _getDeclaredMethod("__first", Class.class, String.class);
		} else if (parameter_len == 1) {m__first = _getDeclaredMethod("__first", Class.class, String.class, Object.class);
		} else if (parameter_len == 2) {m__first = _getDeclaredMethod("__first", Class.class, String.class, Object.class, Object.class);
		} else if (parameter_len >= 3) {m__first = _getDeclaredMethod("__first", Class.class, String.class, Object[].class);
		}
		mWriter.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(parentClass), m__first.getName(), Type.getMethodDescriptor(m__first));
	}
	
	// 调用 __list() 函数
	protected void _visitMethodInsn__list() throws SecurityException, NoSuchMethodException {
		Method m__list = null;
		if (parameter_len == 0) {m__list = _getDeclaredMethod("__list", Class.class, String.class);
		} else if (parameter_len == 1) {m__list = _getDeclaredMethod("__list", Class.class, String.class, Object.class);
		} else if (parameter_len == 2) {m__list = _getDeclaredMethod("__list", Class.class, String.class, Object.class, Object.class);
		} else if (parameter_len >= 3) {m__list = _getDeclaredMethod("__list", Class.class, String.class, Object[].class);
		}
		mWriter.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(parentClass), m__list.getName(), Type.getMethodDescriptor(m__list));
	}
	
	// 获取 searcher 属性
	protected void _visitFieldInsn_searcher() throws SecurityException, NoSuchFieldException, ClassNotFoundException {
		mWriter.visitFieldInsn(GETFIELD, classPath, "searcher", Type.getDescriptor(StandardSearcher.class));
	}
	
	// 获取 scopeFilter 属性
	protected void _visitFieldInsn_scopeFilter() throws SecurityException, NoSuchFieldException {
		mWriter.visitFieldInsn(GETFIELD, classPath, "scopeFilter", Type.getDescriptor(VisibleScopeFilter.class));
	}
	
	// 获取 entityManager 属性
	protected void _visitFieldInsn_entityManager() throws SecurityException, NoSuchFieldException {
		mWriter.visitFieldInsn(GETFIELD, classPath, "entityManager", Type.getDescriptor(EntityManager.class));
	}
	
	// 调用 getEntityReader 函数
	protected void _visitMethodInsn_getEntityReader() throws SecurityException, NoSuchMethodException, ClassNotFoundException {
		Class<StandardSearcher> ssClass = StandardSearcher.class;
		Method m_getEntityReader = ssClass.getDeclaredMethod("getEntityReader", Class.class);
		mWriter.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(ssClass), m_getEntityReader.getName(), Type.getMethodDescriptor(m_getEntityReader));
	}

	// 调用 properties 函数
	protected void _visitMethodInsn_properties() throws SecurityException, NoSuchMethodException {
		Class<EntityReader> erClass = EntityReader.class;
		Method m_properties = erClass.getDeclaredMethod("properties");
		mWriter.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(erClass), m_properties.getName(), Type.getMethodDescriptor(m_properties));
	}
	
	// 调用 filter 函数
	protected void _visitMethodInsn_filter() throws SecurityException, NoSuchMethodException {
		Class<VisibleScopeFilter> vsfClass = VisibleScopeFilter.class;
		Method m_filter = vsfClass.getDeclaredMethod("filter", BaseEvent.class, EntityManager.class, StringBuilder.class, String.class);
		mWriter.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(vsfClass), m_filter.getName(), Type.getMethodDescriptor(m_filter));
	}
	
	// 调用 read 函数
	protected void _visitMethodInsn_read() throws SecurityException, NoSuchMethodException {
		Class<EntityReader> erClass = EntityReader.class;
		Method m_read = erClass.getDeclaredMethod("read", ReadEvent.class, Object.class);
		mWriter.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(erClass), m_read.getName(), Type.getMethodDescriptor(m_read));
	}
	
	// 调用 Page 构造函数
	protected void _visitMethodInsn_Page() throws SecurityException, NoSuchMethodException {
		Class<Page> pClass = Page.class;
		Constructor<Page> c_Page = pClass.getDeclaredConstructor(long.class, List.class);
		mWriter.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(pClass), "<init>", Type.getConstructorDescriptor(c_Page));
	}
	
	// 调用 createQuery 函数
	// 调用 setFirstResult 函数
	// 调用 setMaxResults 函数
	// 调用 getResultList 函数
	// 调用 getSingleResult 函数
	
	// 常量入栈指令
	protected void _constToStack(final int i) {
		final int[] iconsts = {ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5};
		if (i < iconsts.length) {
			mWriter.visitInsn(iconsts[i]);
		} else {
			mWriter.visitVarInsn(BIPUSH, i);
		}
//		if (i == 0) {mWriter.visitInsn(ICONST_0);
//		} else if (i == 1) {mWriter.visitInsn(ICONST_1);
//		} else if (i == 2) {mWriter.visitInsn(ICONST_2);
//		} else if (i == 3) {mWriter.visitInsn(ICONST_3);
//		} else if (i == 4) {mWriter.visitInsn(ICONST_4);
//		} else if (i == 5) {mWriter.visitInsn(ICONST_5);
//		} else {mWriter.visitVarInsn(BIPUSH, i);
//		}
	}
	
	// 加载一个参数、转换为对象类型
	protected void _loadParameter(final String type_desc, final int i) {
		String[] arr_object_type = { Type.getDescriptor(Byte.class), Type.getDescriptor(Short.class),
				Type.getDescriptor(Integer.class), Type.getDescriptor(Long.class), Type.getDescriptor(Float.class),
				Type.getDescriptor(Double.class), Type.getDescriptor(Character.class),
				Type.getDescriptor(Boolean.class), Type.getDescriptor(String.class), Type.getDescriptor(Date.class),
				Type.getDescriptor(Object.class) };
		List<String> object_type = Arrays.asList(arr_object_type);
		if (object_type.contains(type_desc)) {
			mWriter.visitVarInsn(ALOAD, i);
		} else if (type_desc.equals(Type.getDescriptor(byte.class))) {
			mWriter.visitVarInsn(Opcodes.ILOAD, i);
			mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
		} else if (type_desc.equals(Type.getDescriptor(short.class))) {
			mWriter.visitVarInsn(Opcodes.ILOAD, i);
			mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
		} else if (type_desc.equals(Type.getDescriptor(int.class))) {
			mWriter.visitVarInsn(Opcodes.ILOAD, i);
			mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
		} else if (type_desc.equals(Type.getDescriptor(long.class))) {
			mWriter.visitVarInsn(Opcodes.LLOAD, i);
			mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
		} else if (type_desc.equals(Type.getDescriptor(float.class))) {
			mWriter.visitVarInsn(Opcodes.FLOAD, i);
			mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
		} else if (type_desc.equals(Type.getDescriptor(double.class))) {
			mWriter.visitVarInsn(Opcodes.DLOAD, i);
			mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
		} else if (type_desc.equals(Type.getDescriptor(char.class))) {
			mWriter.visitVarInsn(Opcodes.ILOAD, i);
			mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
		} else if (type_desc.equals(Type.getDescriptor(boolean.class))) {
			mWriter.visitVarInsn(Opcodes.ILOAD, i);
			mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
		}
	}
	
	// 加载所有参数
	protected void _loadParameters() {
		if (parameter_len < 3) {
			for (int i = 0, arg_index = 0; i < parameter_len; i++, arg_index++) {
				_loadParameter(parameters[i].getType().getDescriptor(), arg_index + 1);
				if (_parameterIsJD(parameters[i])) {
					arg_index++; // 如果参数为 J、D 类型，占64位
				}
			}
		} else {
			_constToStack(parameter_len);
			mWriter.visitTypeInsn(ANEWARRAY, "java/lang/Object");
			for (int i = 0, arg_index = 0; i < parameter_len; i++, arg_index++) {
				mWriter.visitInsn(DUP);
				_constToStack(i);
				_loadParameter(parameters[i].getType().getDescriptor(), arg_index + 1);
				if (_parameterIsJD(parameters[i])) {
					arg_index++;
				}
				mWriter.visitInsn(AASTORE);
			}
		}
	}
	
	/*
	 * 加载所有参数 qt.setParameter(1, arg1);
	 * 当需要转换类型时，第一个参数为 ReadEvent re，应从第二个参数开始加载，此时 arg_offsets = 1
	 * 当返回 Page 时，第一、第二个参数为 int page, int size，则 arg_offsets = 2
	 */
	protected void _setParameters(int index_query, int arg_offsets) throws SecurityException, NoSuchMethodException {
		Class<Query> tqClass = Query.class;
		Method m_setParameter = tqClass.getDeclaredMethod("setParameter", int.class, Object.class);
		for (int i = 0, arg_index = arg_offsets; i < parameter_len - arg_offsets; i++, arg_index++) {
			mWriter.visitVarInsn(ALOAD, index_query);
			_constToStack(i + 1);
			_loadParameter(parameters[i + arg_offsets].getType().getDescriptor(), arg_index + 1);
			if (_parameterIsJD(parameters[i + arg_offsets])) {
				arg_index++; // 如果参数为 J、D 类型，占64位
			}
			mWriter.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(tqClass), m_setParameter.getName(), Type.getMethodDescriptor(m_setParameter));
			mWriter.visitInsn(POP);
		}
	}
	
	// 判断参数是否为 J、D 类型
	protected boolean _parameterIsJD(final ParameterMetadata parameter) {
		String type_desc = parameter.getType().getDescriptor();
		return type_desc.equals(Type.getDescriptor(long.class)) || type_desc.equals(Type.getDescriptor(double.class));
	}
	
	// 返回参数是 J、D 类型的数量（当参数为 long 或 double 类型，占用64位）
	private int _parameterJDCount() {
		int parameter_JDCount = 0;
		for (ParameterMetadata parameter : parameters) {
			if (_parameterIsJD(parameter)) {
				parameter_JDCount++;
			}
		}
		return parameter_JDCount;
	}
	
	// ql 语句是否查找多项
	protected boolean _isSelectMultiple(String select_val) {
		return StringHelper.getOccur(select_val, "x.") > 1 && select_val.indexOf(",") != 0;
	}
	
	// 不是实体且不属于8种基本类型和11种对象类型，需要转换
	protected boolean _isNeedTransform(final Class<?> resultType) {
		if (null == resultType)
			return false;
		String type_name = resultType.getName();
		String[] array_type = { Byte.class.getName(), Short.class.getName(), Integer.class.getName(),
				Long.class.getName(), Float.class.getName(), Double.class.getName(), Character.class.getName(),
				Boolean.class.getName(), String.class.getName(), Date.class.getName(), Object.class.getName(),
				byte.class.getName(), short.class.getName(), int.class.getName(), long.class.getName(),
				float.class.getName(), double.class.getName(), char.class.getName(), boolean.class.getName() };
		List<String> type = Arrays.asList(array_type);
		return !Persistable.class.isAssignableFrom(resultType) && !type.contains(type_name);
	}

}

/**
 * 返回单个实体
 * <pre>
 * 1.是否指定@From ? 2 : 3;
 * 2.查找@From所定义的类
 * 3.返回类型是否与接口泛型实体(domainClass)相同或是它的父类 ? 4 : 5;
 * 4.查找接口泛型实体domainClass
 * 5.查找返回类型
 * </pre>
 */
class EntityResultType extends ResultType {
	@Override
	public boolean parser(ServiceMethodMetadata smm, Class<?> parentClass, Class<?> entityClass, Class<?> resultType, ClassWriter cw, String classPath, Object extension) throws Exception {
		if (null != resultType && Persistable.class.isAssignableFrom(resultType)) {
			super.parser(smm, parentClass, entityClass, resultType, cw, classPath, extension);
			// 1.生成ql语句
			if (smm.isAnnotated(annotation_select)) {
				Map<String, Object> map = smm.getAnnotationAttributes(annotation_select);
				String select_val = map.get("value").toString();
				ql = "select " + select_val;
			} else {
				ql = "select x";
			}
			if (smm.isAnnotated(annotation_from)) {
				Map<String, Object> map = smm.getAnnotationAttributes(annotation_from);
				String from_val = map.get("value").toString();
				from_val = from_val.substring(1, from_val.length() - 1);
				from_val = ClassUtils.convertResourcePathToClassName(from_val);
				ql += " from " + from_val + " x";
			} else {
				if (returnType.getClass().isAssignableFrom(entityClass)) {
					ql += " from " + entityClass.getName() + " x";
				} else {					
					ql += " from " + returnType + " x";
				}
			}
			if (smm.isAnnotated(annotation_where)) {
				Map<String, Object> map = smm.getAnnotationAttributes(annotation_where);
				String where_val = map.get("value").toString();
				ql += " where " + where_val;
			}

			// 2.处理asm，调用__first()函数
			mWriter.visitVarInsn(ALOAD, 0);
			mWriter.visitLdcInsn(smm.getReturnType());
			mWriter.visitLdcInsn(ql);
			_loadParameters();
			_visitMethodInsn__first();
			mWriter.visitTypeInsn(CHECKCAST, smm.getReturnType().getInternalName());
			mWriter.visitInsn(ARETURN);
			mWriter.visitMaxs(0, 0);
			mWriter.visitEnd();
			return true;
		}
		return false;
	}
}

/**
 * <pre>
 * 0.是否添加 {@link AutoTransform} 注解 ? 3 : 1;
 * 1.是否指定 {@link From} ? 2 : 3;
 * 2.查找 {@link From} 所定义的类
 * 3.查找接口泛型实体domainClass
 * </pre>
 */
class PageResultType extends ResultType {
	@Override
	public boolean parser(ServiceMethodMetadata smm, Class<?> parentClass, Class<?> entityClass, Class<?> resultType, ClassWriter cw, String classPath, Object extension) throws Exception {
		if (null != resultType && Page.class.isAssignableFrom(resultType)) {
			super.parser(smm, parentClass, entityClass, resultType, cw, classPath, extension);
			// 1.生成ql语句
			String ql_count = "select count(x)";
			if (!isHasAutoTransform) {
				if (smm.isAnnotated(annotation_select)) {
					Map<String, Object> map = smm.getAnnotationAttributes(annotation_select);
					String select_val = map.get("value").toString();
					ql = "select " + select_val;
				} else {
					ql = "select x";
				}
				if (smm.isAnnotated(annotation_from)) {
					Map<String, Object> map = smm.getAnnotationAttributes(annotation_from);
					String from_val = map.get("value").toString();
					from_val = from_val.substring(1, from_val.length() - 1);
					from_val = ClassUtils.convertResourcePathToClassName(from_val);
					ql += " from " + from_val + " x";
					ql_count += " from " + from_val + " x";
				} else {
					ql += " from " + entityClass.getName() + " x";
					ql_count += " from " + entityClass.getName() + " x";
				}
			} else {
				ql = " from " + entityClass.getName() + " x";
				ql_count += " from " + entityClass.getName() + " x";
			}
			if (smm.isAnnotated(annotation_where)) {
				Map<String, Object> map = smm.getAnnotationAttributes(annotation_where);
				String where_val = map.get("value").toString();
				ql += " where " + where_val;
				ql_count += " where " + where_val;
			}
			
			if (isHasAutoTransform) { // 自定义类型需要转换
				mWriter.visitVarInsn(ALOAD, 0);
				_visitFieldInsn_searcher();
				if (null != clazz_transform) {
					mWriter.visitLdcInsn(Type.getType(Type.getDescriptor(clazz_transform)));
				}
				_visitMethodInsn_getEntityReader();
				int index_reader = var_index + 1;
				mWriter.visitVarInsn(ASTORE, index_reader);
				
				mWriter.visitVarInsn(ALOAD, 0);
//				mWriter.visitFieldInsn(GETFIELD, classPath, "scopeFilter", "Lcn/bonoon/kernel/support/services/VisibleScopeFilter;");
				_visitFieldInsn_scopeFilter();
				mWriter.visitVarInsn(ALOAD, 3);
				mWriter.visitVarInsn(ALOAD, 0);
//				mWriter.visitFieldInsn(GETFIELD, classPath, "entityManager", "Ljavax/persistence/EntityManager;");
				_visitFieldInsn_entityManager();
				mWriter.visitTypeInsn(NEW, "java/lang/StringBuilder");
				mWriter.visitInsn(DUP);
				mWriter.visitTypeInsn(NEW, "java/lang/StringBuilder");
				mWriter.visitInsn(DUP);
				mWriter.visitLdcInsn("select ");
				mWriter.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
				mWriter.visitVarInsn(ALOAD, index_reader);
//				mWriter.visitMethodInsn(INVOKEVIRTUAL, "cn/bonoon/kernel/bytecode/EntityReader", "properties", "()Ljava/lang/String;");
				_visitMethodInsn_properties();
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
				mWriter.visitLdcInsn(ql);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
				mWriter.visitLdcInsn("");
//				mWriter.visitMethodInsn(
//						INVOKEINTERFACE,
//						"cn/bonoon/kernel/support/services/VisibleScopeFilter",
//						"filter",
//						"(Lcn/bonoon/kernel/support/AbstractEvent;Ljavax/persistence/EntityManager;Ljava/lang/StringBuilder;Ljava/lang/String;)Ljavax/persistence/Query;");
				_visitMethodInsn_filter();
				int index_query = var_index + 2;
				mWriter.visitVarInsn(ASTORE, index_query);
				_setParameters(index_query, 3);
				
				int index_count = var_index + 3;
				mWriter.visitVarInsn(ALOAD, 0);
//				mWriter.visitFieldInsn(GETFIELD, classPath, "entityManager", "Ljavax/persistence/EntityManager;");
				_visitFieldInsn_entityManager();
				mWriter.visitLdcInsn(ql_count);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/EntityManager", "createQuery", "(Ljava/lang/String;)Ljavax/persistence/Query;");
				mWriter.visitVarInsn(ASTORE, index_count);
				_setParameters(index_count, 3);
				
				int index_skig = var_index + 4;
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ILOAD, 1);
				mWriter.visitInsn(ICONST_1);
				mWriter.visitInsn(ISUB);
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Math", "max", "(II)I");
				mWriter.visitVarInsn(ILOAD, 2);
				mWriter.visitInsn(IMUL);
				mWriter.visitVarInsn(ISTORE, index_skig);
				
				mWriter.visitVarInsn(ALOAD, index_query);
				mWriter.visitVarInsn(ILOAD, index_skig);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "setFirstResult", "(I)Ljavax/persistence/Query;");
				mWriter.visitVarInsn(ILOAD, 2);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "setMaxResults", "(I)Ljavax/persistence/Query;");
				mWriter.visitInsn(POP);
				
				int index_objs = var_index + 5;
				mWriter.visitVarInsn(ALOAD, index_query);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "getResultList", "()Ljava/util/List;");
				mWriter.visitVarInsn(ASTORE, index_objs);
				
				int index_rd = var_index + 6;
				mWriter.visitTypeInsn(NEW, "java/util/ArrayList");
				mWriter.visitInsn(DUP);
				mWriter.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V");
				mWriter.visitVarInsn(ASTORE, index_rd);
				
				int index_iterator = var_index + 8;
				mWriter.visitVarInsn(ALOAD, index_objs);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "iterator", "()Ljava/util/Iterator;");
				mWriter.visitVarInsn(ASTORE, index_iterator);
				
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_iterator);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;");
				int index_obj = var_index + 7;
				mWriter.visitVarInsn(ASTORE, index_obj);
				
				mWriter.visitVarInsn(ALOAD, index_reader);
				mWriter.visitVarInsn(ALOAD, 3);
				mWriter.visitVarInsn(ALOAD, index_obj);
//				mWriter.visitMethodInsn(INVOKEVIRTUAL, "cn/bonoon/kernel/bytecode/EntityReader", "read", "(Lcn/bonoon/kernel/support/ReadEvent;Ljava/lang/Object;)Ljava/lang/Object;");
				_visitMethodInsn_read();
				if (null != clazz_transform) {
					mWriter.visitTypeInsn(CHECKCAST, ClassUtils.convertClassNameToResourcePath(clazz_transform.getName()));
				}
				int index_detail = var_index + 9;
				mWriter.visitVarInsn(ASTORE, index_detail);
				
				mWriter.visitVarInsn(ALOAD, index_rd);
				mWriter.visitVarInsn(ALOAD, index_detail);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z");
				mWriter.visitInsn(POP);
				mWriter.visitLabel(start);
				
				mWriter.visitVarInsn(ALOAD, index_iterator);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z");
				mWriter.visitJumpInsn(IFNE, loop);
				
				mWriter.visitVarInsn(ALOAD, index_count);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "getSingleResult", "()Ljava/lang/Object;");
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Number");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J");
				int index_total =  var_index + 7;
				mWriter.visitVarInsn(LSTORE, index_total);
				
				mWriter.visitTypeInsn(NEW, Type.getInternalName(Page.class)); // "cn/bonoon/kernel/support/models/Page"
				mWriter.visitInsn(DUP);
				mWriter.visitVarInsn(LLOAD, index_total);
				mWriter.visitVarInsn(ALOAD, index_rd);
//				mWriter.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Page.class), "<init>", "(JLjava/util/List;)V");
				_visitMethodInsn_Page();
				int index_page = var_index + 9;
				mWriter.visitVarInsn(ASTORE, index_page);
				
				mWriter.visitVarInsn(ALOAD, index_page);
				mWriter.visitInsn(ARETURN);
			} else {
				mWriter.visitVarInsn(ALOAD, 0);
//				mWriter.visitFieldInsn(GETFIELD, classPath, "entityManager", "Ljavax/persistence/EntityManager;");
				_visitFieldInsn_entityManager();
				mWriter.visitLdcInsn(ql);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/EntityManager", "createQuery", "(Ljava/lang/String;)Ljavax/persistence/Query;");
				int index_query = var_index + 1;
				mWriter.visitVarInsn(ASTORE, index_query);
				_setParameters(index_query, 2);
				
				mWriter.visitVarInsn(ALOAD, 0);
//				mWriter.visitFieldInsn(GETFIELD, classPath, "entityManager", "Ljavax/persistence/EntityManager;");
				_visitFieldInsn_entityManager();
				mWriter.visitLdcInsn(ql_count);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/EntityManager", "createQuery", "(Ljava/lang/String;)Ljavax/persistence/Query;");
				int index_count = var_index + 2;
				mWriter.visitVarInsn(ASTORE, index_count);
				_setParameters(index_count, 2);
				
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ILOAD, 1);
				mWriter.visitInsn(ICONST_1);
				mWriter.visitInsn(ISUB);
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Math", "max", "(II)I");
				mWriter.visitVarInsn(ILOAD, 2);
				mWriter.visitInsn(IMUL);
				int index_skig = var_index + 3;
				mWriter.visitVarInsn(ISTORE, index_skig);
				
				mWriter.visitVarInsn(ALOAD, index_query);
				mWriter.visitVarInsn(ILOAD, index_skig);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "setFirstResult", "(I)Ljavax/persistence/Query;");
				mWriter.visitVarInsn(ILOAD, 2);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "setMaxResults", "(I)Ljavax/persistence/Query;");
				mWriter.visitInsn(POP);
				
				mWriter.visitVarInsn(ALOAD, index_query);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "getResultList", "()Ljava/util/List;");
				int index_objs = var_index + 4;
				mWriter.visitVarInsn(ASTORE, index_objs);
				
				mWriter.visitVarInsn(ALOAD, index_count);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "getSingleResult", "()Ljava/lang/Object;");
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Number");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J");
				int index_total = var_index + 5; // long total 64位
				mWriter.visitVarInsn(LSTORE, index_total);
				
				mWriter.visitTypeInsn(NEW, "cn/bonoon/kernel/support/models/Page");
				mWriter.visitInsn(DUP);
				mWriter.visitVarInsn(LLOAD, index_total);
				mWriter.visitVarInsn(ALOAD, index_objs);
				mWriter.visitMethodInsn(INVOKESPECIAL, "cn/bonoon/kernel/support/models/Page", "<init>", "(JLjava/util/List;)V");
				int page = var_index + 7;
				mWriter.visitVarInsn(ASTORE, page);
				
				mWriter.visitVarInsn(ALOAD, page);
				mWriter.visitInsn(ARETURN);
			}
			mWriter.visitMaxs(0, 0);
			mWriter.visitEnd();
			return true;
		}
		return false;
	}
}

/**
 * <pre>
 * 1.是否指定@From ? 2 : 3;
 * 2.查找@From所定义的类
 * 3.函数返回的List<T>中，T是否是实体类型(实现Persistable) ? 4 : 5;
 * 4.T是否与接口泛型实体(domainClass)相同或是它的父类 ? 5 : 6;
 * 5.查找接口泛型实体domainClass
 * 6.查找T
 * </pre>
 */
class CollectionResultType extends ResultType {
	@Override
	public boolean parser(ServiceMethodMetadata smm, Class<?> parentClass, Class<?> entityClass, Class<?> resultType, ClassWriter cw, String classPath, Object extension) throws Exception {
		if (null != resultType && Collection.class.isAssignableFrom(resultType)) {
			super.parser(smm, parentClass, entityClass, resultType, cw, classPath, extension);
			Class<?> genericType = (Class<?>) extension; // T of List<T>
			
			// 1.生成ql语句
			boolean auto_transform = isHasAutoTransform || _isNeedTransform(genericType); // 是否需要类型转换
			boolean select_multiple = false;
			if (!auto_transform) {
				if (smm.isAnnotated(annotation_select)) {
					Map<String, Object> map = smm.getAnnotationAttributes(annotation_select);
					String select_val = map.get("value").toString();
					ql = "select " + select_val;
					select_multiple = _isSelectMultiple(select_val);
				} else {
					ql = "select x";
				}
				if (smm.isAnnotated(annotation_from)) {
					Map<String, Object> map = smm.getAnnotationAttributes(annotation_from);
					String from_val = map.get("value").toString();
					from_val = from_val.substring(1, from_val.length() - 1);
					from_val = ClassUtils.convertResourcePathToClassName(from_val);
					ql += " from " + from_val + " x";
				} else {
					if (Persistable.class.isAssignableFrom(genericType)) {
						if (genericType.getClass().isAssignableFrom(entityClass)) {
							ql += " from " + entityClass.getName() + " x";
						} else {
							ql += " from " + genericType.getName() + " x";
						}
					} else {
						ql += " from " + entityClass.getName() + " x";
					}
				}
			} else {
				ql = " from " + entityClass.getName() + " x";
			}
			if (smm.isAnnotated(annotation_where)) {
				Map<String, Object> map = smm.getAnnotationAttributes(annotation_where);
				String where_val = map.get("value").toString();
				ql += " where " + where_val;
			}

			if (auto_transform) { // 自定义类型转换
				mWriter.visitVarInsn(ALOAD, 0);
//				mWriter.visitFieldInsn(GETFIELD, classPath, "searcher", "Lcn/bonoon/kernel/support/StandardSearcher;");
				_visitFieldInsn_searcher();
				if (isHasAutoTransform && null != clazz_transform) {
					mWriter.visitLdcInsn(Type.getType(Type.getDescriptor(clazz_transform)));
				} else {				
					mWriter.visitLdcInsn(Type.getType(Type.getDescriptor(genericType)));
				}
//				mWriter.visitMethodInsn(INVOKEVIRTUAL, "cn/bonoon/kernel/support/StandardSearcher", "getEntityReader", "(Ljava/lang/Class;)Lcn/bonoon/kernel/bytecode/EntityReader;");
				_visitMethodInsn_getEntityReader();
				int index_reader = var_index + 1;
				mWriter.visitVarInsn(ASTORE, index_reader);
				mWriter.visitVarInsn(ALOAD, 0);
//				mWriter.visitFieldInsn(GETFIELD, classPath, "scopeFilter", "Lcn/bonoon/kernel/support/services/VisibleScopeFilter;");
				_visitFieldInsn_scopeFilter();
				mWriter.visitVarInsn(ALOAD, 1);
				mWriter.visitVarInsn(ALOAD, 0);
//				mWriter.visitFieldInsn(GETFIELD, classPath, "entityManager", "Ljavax/persistence/EntityManager;");
				_visitFieldInsn_entityManager();
				mWriter.visitTypeInsn(NEW, "java/lang/StringBuilder");
				mWriter.visitInsn(DUP);
				mWriter.visitTypeInsn(NEW, "java/lang/StringBuilder");
				mWriter.visitInsn(DUP);
				mWriter.visitLdcInsn("select ");
				mWriter.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
				mWriter.visitVarInsn(ALOAD, index_reader);
//				mWriter.visitMethodInsn(INVOKEVIRTUAL, "cn/bonoon/kernel/bytecode/EntityReader", "properties", "()Ljava/lang/String;");
				_visitMethodInsn_properties();
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
				mWriter.visitLdcInsn(ql);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
				mWriter.visitLdcInsn("");
//				mWriter.visitMethodInsn(
//						INVOKEINTERFACE,
//						"cn/bonoon/kernel/support/services/VisibleScopeFilter",
//						"filter",
//						"(Lcn/bonoon/kernel/support/AbstractEvent;Ljavax/persistence/EntityManager;Ljava/lang/StringBuilder;Ljava/lang/String;)Ljavax/persistence/Query;");
				_visitMethodInsn_filter();
				int index_query = var_index + 2;
				mWriter.visitVarInsn(ASTORE, index_query);
				_setParameters(index_query, 1);
				
				int index_objs = var_index + 3;
				mWriter.visitVarInsn(ALOAD, index_query);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "getResultList", "()Ljava/util/List;");
				mWriter.visitVarInsn(ASTORE, index_objs);
				
				int index_rd = var_index + 4;
				mWriter.visitTypeInsn(NEW, "java/util/ArrayList");
				mWriter.visitInsn(DUP);
				mWriter.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V");
				mWriter.visitVarInsn(ASTORE, index_rd);

				int index_iterator = var_index + 6;
				mWriter.visitVarInsn(ALOAD, index_objs);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "iterator", "()Ljava/util/Iterator;");
				mWriter.visitVarInsn(ASTORE, index_iterator);
				
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_iterator);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;");
				int index_obj = var_index + 5;
				mWriter.visitVarInsn(ASTORE, index_obj);
				
				int index_detail = var_index + 7;
				mWriter.visitVarInsn(ALOAD, index_reader);
				mWriter.visitVarInsn(ALOAD, 1);
				mWriter.visitVarInsn(ALOAD, index_obj);
//				mWriter.visitMethodInsn(INVOKEVIRTUAL, "cn/bonoon/kernel/bytecode/EntityReader", "read", "(Lcn/bonoon/kernel/support/ReadEvent;Ljava/lang/Object;)Ljava/lang/Object;");
				_visitMethodInsn_read();
				if (isHasAutoTransform && null != clazz_transform) {
					mWriter.visitTypeInsn(CHECKCAST, ClassUtils.convertClassNameToResourcePath(clazz_transform.getName()));
				} else {				
					mWriter.visitTypeInsn(CHECKCAST, ClassUtils.convertClassNameToResourcePath(genericType.getName())); // "cn/bonoon/controllers/place/PlaceDetail"
				}
				mWriter.visitVarInsn(ASTORE, index_detail);
				
				mWriter.visitVarInsn(ALOAD, index_rd);
				mWriter.visitVarInsn(ALOAD, index_detail);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z");
				mWriter.visitInsn(POP);
				mWriter.visitLabel(start);
				
				mWriter.visitVarInsn(ALOAD, index_iterator);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z");
				mWriter.visitJumpInsn(IFNE, loop);
				
				mWriter.visitVarInsn(ALOAD, index_rd);
				mWriter.visitInsn(ARETURN);
			} else if (select_multiple) { // select 多个属性
				mWriter.visitVarInsn(ALOAD, 0);
//				mWriter.visitFieldInsn(GETFIELD, classPath, "entityManager", "Ljavax/persistence/EntityManager;");
				_visitFieldInsn_entityManager();
				mWriter.visitLdcInsn(ql);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/EntityManager", "createQuery", "(Ljava/lang/String;)Ljavax/persistence/Query;");
				int index_query = var_index + 1;
				mWriter.visitVarInsn(ASTORE, index_query);
				_setParameters(index_query, 0);
				mWriter.visitVarInsn(ALOAD, index_query);
				mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "getResultList", "()Ljava/util/List;");
				int index_list = var_index + 2;
				mWriter.visitVarInsn(ASTORE, index_list);
				mWriter.visitVarInsn(ALOAD, index_list);
				mWriter.visitInsn(ARETURN);
			} else {
				// 2.处理asm，调用__list()函数
				mWriter.visitVarInsn(ALOAD, 0);
				mWriter.visitLdcInsn(Type.getType(Type.getDescriptor(genericType)));
				mWriter.visitLdcInsn(ql);
				_loadParameters();
				_visitMethodInsn__list();
				mWriter.visitInsn(ARETURN);
			}
			mWriter.visitMaxs(0, 0);
			mWriter.visitEnd();
			return true;
		}
		return false;
	}
}

/**
 * <pre>
 * 1.是否指定@From ? 2 : 3;
 * 2.查找@From所定义的类
 * 3.查找接口泛型实体domainClass
 * </pre>
 */
class ArrayResultType extends ResultType {
	@Override
	public boolean parser(ServiceMethodMetadata smm, Class<?> parentClass, Class<?> entityClass, Class<?> resultType, ClassWriter cw, String classPath, Object extension) throws Exception {
		if (null != resultType && resultType.isArray()) {
			super.parser(smm, parentClass, entityClass, resultType, cw, classPath, extension);
			// 1.生成ql语句
			if (smm.isAnnotated(annotation_select)) {
				Map<String, Object> map = smm.getAnnotationAttributes(annotation_select);
				String select_val = map.get("value").toString();
				ql = "select " + select_val;
			} else {
				ql = "select x";
			}
			if (smm.isAnnotated(annotation_from)) {
				Map<String, Object> map = smm.getAnnotationAttributes(annotation_from);
				String from_val = map.get("value").toString();
				from_val = from_val.substring(1, from_val.length() - 1);
				from_val = ClassUtils.convertResourcePathToClassName(from_val);
				ql += " from " + from_val + " x";
			} else {
				ql += " from " + entityClass.getName() + " x";
			}
			if (smm.isAnnotated(annotation_where)) {
				Map<String, Object> map = smm.getAnnotationAttributes(annotation_where);
				String where_val = map.get("value").toString();
				ql += " where " + where_val;
			}
			
			// 2.处理asm，调用getEntityManager().createQuery()函数
			mWriter.visitVarInsn(ALOAD, 0);
//			mWriter.visitFieldInsn(GETFIELD, classPath, "entityManager", "Ljavax/persistence/EntityManager;");
			_visitFieldInsn_entityManager();
			mWriter.visitLdcInsn(ql);
			mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/EntityManager", "createQuery", "(Ljava/lang/String;)Ljavax/persistence/Query;");
			int index_query = var_index + 1; // 第一个变量(Query tq)
			int index_array_object = var_index + 2; // 第二个变量(Object[] objs)
			mWriter.visitVarInsn(ASTORE, index_query); 
			_setParameters(index_query, 0);
			mWriter.visitVarInsn(ALOAD, index_query);
			mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "getSingleResult", "()Ljava/lang/Object;");
			mWriter.visitTypeInsn(CHECKCAST, "[Ljava/lang/Object;");
			mWriter.visitVarInsn(ASTORE, index_array_object); 
			mWriter.visitVarInsn(ALOAD, index_array_object);
			
			// 3.如果不是返回 Object[]，需要类型转换
			String array_type = resultType.getComponentType().getName();
			if (array_type.equals(Byte.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_Byte = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitTypeInsn(ANEWARRAY, "java/lang/Byte");
				mWriter.visitVarInsn(ASTORE, index_array_Byte);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_Byte);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(Ljava/lang/String;)Ljava/lang/Byte;");
				mWriter.visitInsn(AASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_Byte);
			} else if (array_type.equals(Short.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_Short = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitTypeInsn(ANEWARRAY, "java/lang/Short");
				mWriter.visitVarInsn(ASTORE, index_array_Short);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_Short);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(Ljava/lang/String;)Ljava/lang/Short;");
				mWriter.visitInsn(AASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_Short);
			} else if (array_type.equals(Integer.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_Integer = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitTypeInsn(ANEWARRAY, "java/lang/Integer");
				mWriter.visitVarInsn(ASTORE, index_array_Integer);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_Integer);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(Ljava/lang/String;)Ljava/lang/Integer;");
				mWriter.visitInsn(AASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_Integer);
			} else if (array_type.equals(Long.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_Long = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitTypeInsn(ANEWARRAY, "java/lang/Long");
				mWriter.visitVarInsn(ASTORE, index_array_Long);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_Long);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(Ljava/lang/String;)Ljava/lang/Long;");
				mWriter.visitInsn(AASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_Long);
			} else if (array_type.equals(Float.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_Float = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitTypeInsn(ANEWARRAY, "java/lang/Float");
				mWriter.visitVarInsn(ASTORE, index_array_Float);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_Float);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(Ljava/lang/String;)Ljava/lang/Float;");
				mWriter.visitInsn(AASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_Float);
			} else if (array_type.equals(Double.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_Double = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitTypeInsn(ANEWARRAY, "java/lang/Double");
				mWriter.visitVarInsn(ASTORE, index_array_Double);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_Double);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(Ljava/lang/String;)Ljava/lang/Double;");
				mWriter.visitInsn(AASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_Double);
			} else if (array_type.equals(Character.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_Character = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitTypeInsn(ANEWARRAY, "java/lang/Character");
				mWriter.visitVarInsn(ASTORE, index_array_Character);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_Character);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Character");
				mWriter.visitInsn(AASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_Character);
			} else if (array_type.equals(Boolean.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_Boolean = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitTypeInsn(ANEWARRAY, "java/lang/Boolean");
				mWriter.visitVarInsn(ASTORE, index_array_Boolean);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_Boolean);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Ljava/lang/String;)Ljava/lang/Boolean;");
				mWriter.visitInsn(AASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_Boolean);
			} else if (array_type.equals(String.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_String = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitTypeInsn(ANEWARRAY, "java/lang/String");
				mWriter.visitVarInsn(ASTORE, index_array_String);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_String);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitInsn(AASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_String);
			} else if (array_type.equals(Date.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_Date = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitTypeInsn(ANEWARRAY, "java/util/Date");
				mWriter.visitVarInsn(ASTORE, index_array_Date);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_Date);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitTypeInsn(CHECKCAST, "java/util/Date");
				mWriter.visitInsn(AASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_Date);
			} else if (array_type.equals(byte.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_byte = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitIntInsn(NEWARRAY, T_BYTE);
				mWriter.visitVarInsn(ASTORE, index_array_byte);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_byte);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(Ljava/lang/String;)Ljava/lang/Byte;");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
				mWriter.visitInsn(BASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_byte);
			} else if (array_type.equals(short.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_short = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitIntInsn(NEWARRAY, T_SHORT);
				mWriter.visitVarInsn(ASTORE, index_array_short);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_short);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(Ljava/lang/String;)Ljava/lang/Short;");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
				mWriter.visitInsn(SASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_short);
			} else if (array_type.equals(int.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_int = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitIntInsn(NEWARRAY, T_INT);
				mWriter.visitVarInsn(ASTORE, index_array_int);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_int);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(Ljava/lang/String;)Ljava/lang/Integer;");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
				mWriter.visitInsn(IASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_int);
			} else if (array_type.equals(long.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_long = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitIntInsn(NEWARRAY, T_LONG);
				mWriter.visitVarInsn(ASTORE, index_array_long);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_long);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(Ljava/lang/String;)Ljava/lang/Long;");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
				mWriter.visitInsn(LASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_long);
			} else if (array_type.equals(float.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_float = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitIntInsn(NEWARRAY, T_FLOAT);
				mWriter.visitVarInsn(ASTORE, index_array_float);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_float);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(Ljava/lang/String;)Ljava/lang/Float;");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
				mWriter.visitInsn(FASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_float);
			} else if (array_type.equals(double.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_double = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitIntInsn(NEWARRAY, T_DOUBLE);
				mWriter.visitVarInsn(ASTORE, index_array_double);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_double);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
				mWriter.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(Ljava/lang/String;)Ljava/lang/Double;");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
				mWriter.visitInsn(DASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_double);
			} else if (array_type.equals(char.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_char = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitIntInsn(NEWARRAY, T_CHAR);
				mWriter.visitVarInsn(ASTORE, index_array_char);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_char);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Character");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
				mWriter.visitInsn(CASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_char);
			} else if (array_type.equals(boolean.class.getName())) {
				int index_array_object_len = var_index + 3;
				int index_array_boolean = var_index + 4;
				int index_i = var_index + 5;
				mWriter.visitInsn(ARRAYLENGTH);
				mWriter.visitVarInsn(ISTORE, index_array_object_len);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitIntInsn(NEWARRAY, T_BOOLEAN);
				mWriter.visitVarInsn(ASTORE, index_array_boolean);
				mWriter.visitInsn(ICONST_0);
				mWriter.visitVarInsn(ISTORE, index_i);
				Label start = new Label();
				Label loop = new Label();
				mWriter.visitJumpInsn(GOTO, start);
				mWriter.visitLabel(loop);
				mWriter.visitVarInsn(ALOAD, index_array_boolean);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ALOAD, index_array_object);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitInsn(AALOAD);
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
				mWriter.visitInsn(BASTORE);
				mWriter.visitIincInsn(index_i, 1);
				mWriter.visitLabel(start);
				mWriter.visitVarInsn(ILOAD, index_i);
				mWriter.visitVarInsn(ILOAD, index_array_object_len);
				mWriter.visitJumpInsn(IF_ICMPLT, loop);
				mWriter.visitVarInsn(ALOAD, index_array_boolean);
			}
			mWriter.visitInsn(ARETURN);
			mWriter.visitMaxs(0, 0);
			mWriter.visitEnd();
			return true;
		}
		return false;
	}
}

/**
 * <pre>
 * 1.是否指定@From ? 2 : 3;
 * 2.查找@From所定义的类
 * 3.查找接口泛型实体domainClass
 * </pre>
 */
class ObjectResultType extends ResultType {
	@Override
	public boolean parser(ServiceMethodMetadata smm, Class<?> parentClass, Class<?> entityClass, Class<?> resultType, ClassWriter cw, String classPath, Object extension) throws Exception {
		super.parser(smm, parentClass, entityClass, resultType, cw, classPath, extension);
		// 1.生成ql语句
		boolean auto_transform = isHasAutoTransform || _isNeedTransform(resultType); // 是否需要类型转换
		if (!auto_transform) {
			if (smm.isAnnotated(annotation_select)) {
				Map<String, Object> map = smm.getAnnotationAttributes(annotation_select);
				String select_val = map.get("value").toString();
				ql = "select " + select_val;
			} else {
				ql = "select x";
			}
			if (smm.isAnnotated(annotation_from)) {
				Map<String, Object> map = smm.getAnnotationAttributes(annotation_from);
				String from_val = map.get("value").toString();
				from_val = from_val.substring(1, from_val.length() - 1);
				from_val = ClassUtils.convertResourcePathToClassName(from_val);
				ql += " from " + from_val + " x";
			} else {
				ql += " from " + entityClass.getName() + " x";
			}
		} else {
			ql = " from " + entityClass.getName() + " x";
		}
		if (smm.isAnnotated(annotation_where)) {
			Map<String, Object> map = smm.getAnnotationAttributes(annotation_where);
			String where_val = map.get("value").toString();
			ql += " where " + where_val;
		}

		// 2.处理asm，调用__first()函数，返回数据类型转换
		if (auto_transform) { // 自定义对象类型，需要转换的对象类型
			mWriter.visitVarInsn(ALOAD, 0);
//			mWriter.visitFieldInsn(GETFIELD, classPath, "searcher", "Lcn/bonoon/kernel/support/StandardSearcher;");
			_visitFieldInsn_searcher();
			if (isHasAutoTransform && null != clazz_transform) {
				mWriter.visitLdcInsn(Type.getType(Type.getDescriptor(clazz_transform)));
			} else {				
				mWriter.visitLdcInsn(Type.getType(Type.getDescriptor(resultType)));
			}
//			mWriter.visitMethodInsn(INVOKEVIRTUAL, "cn/bonoon/kernel/support/StandardSearcher", "getEntityReader", "(Ljava/lang/Class;)Lcn/bonoon/kernel/bytecode/EntityReader;");
			_visitMethodInsn_getEntityReader();
			int index_reader = var_index + 1;
			mWriter.visitVarInsn(ASTORE, index_reader);
			
			mWriter.visitVarInsn(ALOAD, 0);
//			mWriter.visitFieldInsn(GETFIELD, classPath, "scopeFilter", "Lcn/bonoon/kernel/support/services/VisibleScopeFilter;");
			_visitFieldInsn_scopeFilter();
			mWriter.visitVarInsn(ALOAD, 1);
			mWriter.visitVarInsn(ALOAD, 0);
//			mWriter.visitFieldInsn(GETFIELD, classPath, "entityManager", "Ljavax/persistence/EntityManager;");
			_visitFieldInsn_entityManager();
			mWriter.visitTypeInsn(NEW, "java/lang/StringBuilder");
			mWriter.visitInsn(DUP);
			mWriter.visitTypeInsn(NEW, "java/lang/StringBuilder");
			mWriter.visitInsn(DUP);
			mWriter.visitLdcInsn("select ");
			mWriter.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
			mWriter.visitVarInsn(ALOAD, index_reader);
//			mWriter.visitMethodInsn(INVOKEVIRTUAL, "cn/bonoon/kernel/bytecode/EntityReader", "properties", "()Ljava/lang/String;");
			_visitMethodInsn_properties();
			mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
			mWriter.visitLdcInsn(ql);
			mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
			mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
			mWriter.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
			
			mWriter.visitLdcInsn("");
//			mWriter.visitMethodInsn(
//					INVOKEINTERFACE,
//					"cn/bonoon/kernel/support/services/VisibleScopeFilter",
//					"filter",
//					"(Lcn/bonoon/kernel/support/AbstractEvent;Ljavax/persistence/EntityManager;Ljava/lang/StringBuilder;Ljava/lang/String;)Ljavax/persistence/Query;");
			_visitMethodInsn_filter();
			int index_query = var_index + 2;
			mWriter.visitVarInsn(ASTORE, index_query);
			_setParameters(index_query, 1);
			
			mWriter.visitVarInsn(ALOAD, index_query);
			mWriter.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "getResultList", "()Ljava/util/List;");
			mWriter.visitInsn(ICONST_0);
			mWriter.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;");
			int index_obj = var_index + 3;
			mWriter.visitVarInsn(ASTORE, index_obj);
			
			mWriter.visitVarInsn(ALOAD, index_reader);
			mWriter.visitVarInsn(ALOAD, 1);
			mWriter.visitVarInsn(ALOAD, index_obj);
//			mWriter.visitMethodInsn(INVOKEVIRTUAL, "cn/bonoon/kernel/bytecode/EntityReader", "read", "(Lcn/bonoon/kernel/support/ReadEvent;Ljava/lang/Object;)Ljava/lang/Object;");
			_visitMethodInsn_read();
			if (isHasAutoTransform && null != clazz_transform) {
				mWriter.visitTypeInsn(CHECKCAST, ClassUtils.convertClassNameToResourcePath(clazz_transform.getName()));
			} else {				
				mWriter.visitTypeInsn(CHECKCAST, smm.getReturnType().getInternalName()); // "cn/bonoon/controllers/place/PlaceDetail"
			}
			mWriter.visitInsn(ARETURN);
		} else if (null != resultType && null == extension) { // 11种对象类型，不需要转换类型
			mWriter.visitVarInsn(ALOAD, 0);
			mWriter.visitLdcInsn(smm.getReturnType());
			mWriter.visitLdcInsn(ql);
			_loadParameters();
			_visitMethodInsn__first();
			mWriter.visitTypeInsn(CHECKCAST, smm.getReturnType().getInternalName());
			// mWriter.visitInsn(ACONST_NULL);
			mWriter.visitInsn(ARETURN);
		} else { // 基本类型
			mWriter.visitVarInsn(ALOAD, 0);
			String return_type = extension.toString();
			if (return_type.equals(byte.class.getName())) {
				mWriter.visitLdcInsn(Type.getType("Ljava/lang/Byte;"));
				mWriter.visitLdcInsn(ql);
				_loadParameters();
				_visitMethodInsn__first();
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Byte");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
				mWriter.visitInsn(IRETURN);
			} else if (return_type.equals(short.class.getName())) {
				mWriter.visitLdcInsn(Type.getType("Ljava/lang/Short;"));
				mWriter.visitLdcInsn(ql);
				_loadParameters();
				_visitMethodInsn__first();
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Short");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
				mWriter.visitInsn(IRETURN);
			} else if (return_type.equals(int.class.getName())) {
				mWriter.visitLdcInsn(Type.getType("Ljava/lang/Integer;"));
				mWriter.visitLdcInsn(ql);
				_loadParameters();
				_visitMethodInsn__first();
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Integer");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
				mWriter.visitInsn(IRETURN);
			} else if (return_type.equals(long.class.getName())) {
				mWriter.visitLdcInsn(Type.getType("Ljava/lang/Long;"));
				mWriter.visitLdcInsn(ql);
				_loadParameters();
				_visitMethodInsn__first();
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Long");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
				mWriter.visitInsn(LRETURN);
			} else if (return_type.equals(float.class.getName())) {
				mWriter.visitLdcInsn(Type.getType("Ljava/lang/Float;"));
				mWriter.visitLdcInsn(ql);
				_loadParameters();
				_visitMethodInsn__first();
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Float");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
				mWriter.visitInsn(FRETURN);
			} else if (return_type.equals(double.class.getName())) {
				mWriter.visitLdcInsn(Type.getType("Ljava/lang/Double;"));
				mWriter.visitLdcInsn(ql);
				_loadParameters();
				_visitMethodInsn__first();
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Double");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
				mWriter.visitInsn(DRETURN);
			} else if (return_type.equals(char.class.getName())) {
				mWriter.visitLdcInsn(Type.getType("Ljava/lang/Character;"));
				mWriter.visitLdcInsn(ql);
				_loadParameters();
				_visitMethodInsn__first();
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Character");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
				mWriter.visitInsn(IRETURN);
			} else if (return_type.equals(boolean.class.getName())) {
				mWriter.visitLdcInsn(Type.getType("Ljava/lang/Boolean;"));
				mWriter.visitLdcInsn(ql);
				_loadParameters();
				_visitMethodInsn__first();
				mWriter.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
				mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
				mWriter.visitInsn(IRETURN);
			}
		}
		mWriter.visitMaxs(0, 0);
		mWriter.visitEnd();
		return true;
	}
}